#ifndef UHM_MAT_LINAL_MAT_HXX_
#define UHM_MAT_LINAL_MAT_HXX_

namespace uhm {
  inline FLA_Obj& int2fla(Int_ alpha) {
    switch(alpha) {
    case -1: return FLA_MINUS_ONE;
    case  0: return FLA_ZERO;
    case  1: return FLA_ONE;
    }
    UHM_ERROR(false, UHM_ERROR_MAT2LINAL);
    return FLA_ZERO;
  }

  inline Int_ type2linal(Int_ type) {
    switch(type) {
    case Mat_Base_::INT    : return LINAL_INT;
    case Mat_Base_::FLOAT  : return LINAL_SINGLE_REAL;
    case Mat_Base_::DOUBLE : return LINAL_DOUBLE_REAL;
    case Mat_Base_::FCMPLX : return LINAL_SINGLE_COMPLEX;
    case Mat_Base_::DCMPLX : return LINAL_DOUBLE_COMPLEX;
    }
    UHM_ERROR(false, UHM_ERROR_MAT2LINAL);
    return 0;
  }

  inline Int_ type2linal_real(Int_ type) {
    switch(type) {
    case Mat_Base_::INT    : 
      return LINAL_INT;
    case Mat_Base_::FLOAT  : 
    case Mat_Base_::FCMPLX : 
      return LINAL_SINGLE_REAL;
    case Mat_Base_::DCMPLX :
    case Mat_Base_::DOUBLE :
      return LINAL_DOUBLE_REAL;
    }
    UHM_ERROR(false, UHM_ERROR_MAT2LINAL);
    return 0;
  }

  inline Int_ side2linal(Int_ side) {
    switch(side) {
    case Mat_Base_::LEFT  : return LINAL_LEFT;
    case Mat_Base_::RIGHT : return LINAL_RIGHT;
    }
    UHM_ERROR(false, UHM_ERROR_MAT2LINAL);
    return 0;
  }

  inline Int_ trans2linal(Int_ trans) {
    switch(trans) {
    case Mat_Base_::TRANSPOSE      : return LINAL_TRANSPOSE;
    case Mat_Base_::NO_TRANSPOSE   : return LINAL_NO_TRANSPOSE;
    case Mat_Base_::CONJ_TRANSPOSE : return LINAL_CONJ_TRANSPOSE;
    }
    UHM_ERROR(false, UHM_ERROR_MAT2LINAL);
    return 0;
  }
  
  inline Int_ diag2linal(Int_ diag) { 
    switch(diag) {
    case Mat_Base_::ZERO_DIAG    : return LINAL_ZERO_DIAG; 
    case Mat_Base_::NONUNIT_DIAG : return LINAL_NONUNIT_DIAG;
    case Mat_Base_::UNIT_DIAG    : return LINAL_UNIT_DIAG;
    }
    UHM_ERROR(false, UHM_ERROR_MAT2LINAL);
    return 0;
  }
  
  inline Int_ uplo2linal(Int_ uplo) {
    switch(uplo) {
    case Mat_Base_::FULL             : return LINAL_LOWER_TRIANGULAR;
    case Mat_Base_::LOWER_TRIANGULAR : return LINAL_LOWER_TRIANGULAR;
    case Mat_Base_::UPPER_TRIANGULAR : return LINAL_UPPER_TRIANGULAR;
    }
    UHM_ERROR(false, UHM_ERROR_MAT2LINAL);
    return 0;
  }
  
  inline Int_ conj2linal(Int_ conj) {
    switch(conj) {
    case Mat_Base_::CONJUGATE    : return LINAL_CONJUGATE;
    case Mat_Base_::NO_CONJUGATE : return LINAL_NO_CONJUGATE;
    }
    UHM_ERROR(false, UHM_ERROR_MAT2LINAL);
    return 0;
  }

  inline Int_ inv2linal(Int_ inv) {
    switch(inv) {
    case Mat_Base_::INVERSE    : return LINAL_INVERSE;
    case Mat_Base_::NO_INVERSE : return LINAL_NO_INVERSE;
    }
    UHM_ERROR(false, UHM_ERROR_MAT2LINAL);
    return 0;
  }

  typedef class Mat_< linal::Flat_,linal::Hier_> Mat_Linal_;

  template<> void Mat_Linal_::create_flat_without_buffer();
  template<> void Mat_Linal_::create_flat_buffer(); 
  template<> void Mat_Linal_::free_flat_buffer(); 

  template<> void* Mat_Linal_::get_flat_buffer(Int_ offn) const;

  template<> void Mat_Linal_::attach_flat_buffer(Int_ cs, Int_ rs, void *buffer);
  template<> void Mat_Linal_::free_flat_without_buffer();

  template<> void Mat_Linal_::create_hier(Int_ mb, Int_ nb); 
  template<> void Mat_Linal_::free_hier(); 
  //template<> void Mat_Linal_::free_all(); 
  template<> void Mat_Linal_::set_zero(); 
  template<> void Mat_Linal_::set_identity(); 
  template<> void Mat_Linal_::hermitianize(); 
  template<> void Mat_Linal_::transpose(); 
  template<> Bool_ Mat_Linal_::is_flat_buffer_null(); 

  /*
  template<> void Mat_Linal_::create_flat_without_buffer() {
    _flat.create_without_buffer( type2linal(_type), _m, _n );
  }
  template<> void Mat_Linal_::create_flat_buffer() {
    _flat.create_buffer();
  }
  template<> void Mat_Linal_::free_flat_buffer() {
    _flat.free_buffer();
  }
  template<> void Mat_Linal_::create_hier(Int_ mb, Int_ nb) {
    _hier.create(_flat, mb, nb);
  }
  template<> void Mat_Linal_::free_hier() {
    _hier.free();
  }
  template<> void Mat_Linal_::free_all() {
    _hier.free(); _flat.free();
  }
  template<> void Mat_Linal_::set_zero() {
    _flat.set_zero();
  }
  template<> Bool_ Mat_Linal_::is_flat_buffer_null() {
    return _flat.is_buffer_null();
  }
  */
}


#endif
